/* 
 *	Copyright (C) 2009-2010 miaohua
 *	http://code.google.com/p/lrcshower/
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include "StdAfx.h"
#include <Streams.h>
#include <string>
#include "TypeDef.h"
#include "ColorButton.h"
#include "MusicBoxSetting.h"


extern MusicBoxSetting Gbl_AppProp;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CColorButton

CColorButton::CColorButton(COLORREF * Clrs, int ClrNum)
{
     m_BoundryPen.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0, 60, 116));
     m_InsideBoundryPenLeft.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(250, 196, 88)); 
     m_InsideBoundryPenRight.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(251, 202, 106));
     m_InsideBoundryPenTop.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(252, 210, 121));
     m_InsideBoundryPenBottom.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(229, 151, 0));

     m_FillActive.CreateSolidBrush(RGB(223, 222, 236));
     m_FillInactive.CreateSolidBrush(RGB(222, 223, 236));

     m_InsideBoundryPenLeftSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(153, 198, 252)); 
     m_InsideBoundryPenRightSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 3, RGB(162, 189, 252));
     m_InsideBoundryPenTopSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));
     m_InsideBoundryPenBottomSel.CreatePen(PS_INSIDEFRAME | PS_SOLID, 2, RGB(162, 201, 255));

     m_IsHangOver = m_IsSelected = m_IsTracking = m_IsFocus = FALSE;

     m_Clrs = Clrs;
     m_ClrNum = ClrNum;
}

CColorButton::~CColorButton()
{
     m_BoundryPen.DeleteObject();
     m_InsideBoundryPenLeft.DeleteObject();
     m_InsideBoundryPenRight.DeleteObject();
     m_InsideBoundryPenTop.DeleteObject();
     m_InsideBoundryPenBottom.DeleteObject();

     m_FillActive.DeleteObject();
     m_FillInactive.DeleteObject();

     m_InsideBoundryPenLeftSel.DeleteObject();
     m_InsideBoundryPenTopSel.DeleteObject();
     m_InsideBoundryPenRightSel.DeleteObject();
     m_InsideBoundryPenBottomSel.DeleteObject();
}


BEGIN_MESSAGE_MAP(CColorButton, CButton)
     //{{AFX_MSG_MAP(CColorButton)
     ON_WM_MOUSEMOVE()
     ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
     ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CColorButton message handlers

void CColorButton::OnMouseMove(UINT nFlags, CPoint point) 
{
     if( !m_IsTracking )
     {
	     TRACKMOUSEEVENT Tme;
	     Tme.cbSize = sizeof(Tme);
	     Tme.hwndTrack = m_hWnd;
	     Tme.dwFlags = TME_LEAVE | TME_HOVER;
	     Tme.dwHoverTime = 1;
	     m_IsTracking = _TrackMouseEvent(&Tme);
     }

     CButton::OnMouseMove(nFlags, point);
}


LRESULT CColorButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
     m_IsHangOver = FALSE;
     m_IsTracking = FALSE;
     InvalidateRect(NULL, FALSE);
     return 0;
}

LRESULT CColorButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{
     m_IsHangOver = TRUE;
     InvalidateRect(NULL);
     return 0;
}


void CColorButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
     CRect Rect = lpDrawItemStruct->rcItem;
	 CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
	 int PreSaveDC = pDC->SaveDC();
	
     // Draw outline of button with semi-circle corners(radius=5)
     POINT Pt = {5,5};
     CPen* OldPen = pDC->SelectObject(&m_BoundryPen);
     pDC->RoundRect(&Rect, Pt);
	 pDC->SelectObject(OldPen);
	
     // Get button state
     UINT State = lpDrawItemStruct->itemState;
     if( State & ODS_FOCUS )
     {
         m_IsFocus = TRUE;
         m_IsSelected = TRUE;
     } else {
		m_IsFocus = FALSE;
		m_IsSelected = FALSE;
	 }
	 if( State & ODS_SELECTED || State & ODS_DEFAULT )
		 m_IsFocus = TRUE;
  
     // ?
	 Rect.DeflateRect(CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));
	
     // Fill background according current state
     CBrush * OldBrush = NULL;
     if( m_IsHangOver )
     {
	     OldBrush = pDC->SelectObject(&m_FillActive);
	     DoGradientFill(pDC, Rect);
     }
     else
     {
	     OldBrush = pDC->SelectObject(&m_FillInactive);
	     DoGradientFill(pDC, Rect);
     }
	
     // Draw inner boundary
     if( m_IsHangOver || m_IsSelected )
	     DrawInsideBorder(pDC, Rect);
	 // Restore old brush			
	 pDC->SelectObject(OldBrush);
	
     // Draw selected color
     LPDRAWITEMSTRUCT dis = lpDrawItemStruct;
     LOGBRUSH lb;
     lb.lbStyle = BS_SOLID;
     RECT ClrRc = dis->rcItem;
     ClrRc.right /= 3;
     ClrRc.left += 3;
     ClrRc.top += 3;
     ClrRc.bottom -= 3;
     LONG Dis = (ClrRc.bottom - ClrRc.top)/m_ClrNum;
     ClrRc.bottom = ClrRc.top;
     for( int i = 0; i < m_ClrNum; ++i )
     {
          // Set color
          lb.lbColor = m_Clrs[i];
          HBRUSH br = CreateBrushIndirect(&lb);
          // Set painted rectangle
          ClrRc.top = ClrRc.bottom;
          ClrRc.bottom += Dis;
          // Paint
          FillRect(dis->hDC, &ClrRc, br);
          DeleteObject(br);
     }

	 // Draw text
     CString Title;
     GetWindowText(Title);
	 if( !Title.IsEmpty() )
	 {
		 CFont* Font = GetFont();
		 CFont* OldFont = pDC->SelectObject(Font);
		 CSize Extent = pDC->GetTextExtent(Title);
		 CPoint Pt( Rect.left+Rect.Width()*2/3 - Extent.cx/2, Rect.CenterPoint().y - Extent.cy / 2);
		 if( State & ODS_SELECTED ) 
			 Pt.Offset(1, 1);
		 int Mode = pDC->SetBkMode(TRANSPARENT);
		 if( State & ODS_DISABLED )
			 pDC->DrawState(Pt, Extent, Title, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
		 else
			 pDC->DrawState(Pt, Extent, Title, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);
		 pDC->SelectObject(OldFont);
		 pDC->SetBkMode(Mode);
	}
	
     // Restore previous saved dc
     pDC->RestoreDC(PreSaveDC);
}


void CColorButton::DoGradientFill(CDC *pDC, const CRect & Rect)
{
	 CBrush BrBk[64];
	 CRect  Rc;
	
	 for( int i = 0; i < 64; ++i )
	 {
		  if( m_IsHangOver )
		  {
			  if( m_IsFocus )
				  BrBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 3)));
			  else
				  BrBk[i].CreateSolidBrush(RGB(255 - (i / 4), 255 - (i / 4), 255 - (i / 5)));
		  } else {
			  if( m_IsFocus )
				  BrBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 4)));
			  else
				  BrBk[i].CreateSolidBrush(RGB(255 - (i / 3), 255 - (i / 3), 255 - (i / 5)));
		  }
     }
     	
     int Width = Rect.Width();	
     int Height = Rect.Height();

     for( int i = Rect.top; i <= Height + 2; ++i ) 
     {
	      Rc.SetRect(Rect.left, i, Width + 2, i + 1);
	      pDC->FillRect(&Rc, &BrBk[((i * 63) / Height)]);
     }

     for( int i = 0; i < 64; ++i )
	      BrBk[i].DeleteObject();
}



void CColorButton::DrawInsideBorder(CDC *pDC, const CRect & Rect)
{
     CPen *LeftPen, *RightPen, *TopPen, *BottomPen;

     if( m_IsSelected && !m_IsHangOver )
     {
	     LeftPen   = &m_InsideBoundryPenLeftSel;
	     RightPen  = &m_InsideBoundryPenRightSel;
	     TopPen    = &m_InsideBoundryPenTopSel;
	     BottomPen = &m_InsideBoundryPenBottomSel;
     } else {
	     LeftPen   = &m_InsideBoundryPenLeft;
	     RightPen  = &m_InsideBoundryPenRight;
	     TopPen    = &m_InsideBoundryPenTop;
	     BottomPen = &m_InsideBoundryPenBottom;
     }
	
     CPoint OldPoint = pDC->MoveTo(Rect.left, Rect.bottom-1);
     CPen* OldPen = pDC->SelectObject(LeftPen);
     pDC->LineTo(Rect.left, Rect.top+1);
     pDC->SelectObject(RightPen);
     pDC->MoveTo(Rect.right-1, Rect.bottom-1);
     pDC->LineTo(Rect.right-1, Rect.top);
     pDC->SelectObject(TopPen);
     pDC->MoveTo(Rect.left-1, Rect.top);
     pDC->LineTo(Rect.right-1, Rect.top);
     pDC->SelectObject(BottomPen);
     pDC->MoveTo(Rect.left, Rect.bottom);
     pDC->LineTo(Rect.right-1, Rect.bottom);
     pDC->SelectObject(OldPen);
     pDC->MoveTo(OldPoint);

     if( m_IsSelected && !m_IsHangOver )
		 DrawFocusRect(pDC->m_hDC,Rect);
}


